package com.swanclouds.redfish.provider;

import com.google.common.collect.Maps;
import com.swanclouds.api.APIProvider;
import com.swanclouds.api.account.AccountService;
import com.swanclouds.api.account.HuaWei.HuaWeiAccountService;
import com.swanclouds.api.account.LdapService;
import com.swanclouds.api.chassis.*;
import com.swanclouds.api.event.EventResourceService;
import com.swanclouds.api.event.SubscriptionsService;
import com.swanclouds.api.exceptions.ApiNotFoundException;
import com.swanclouds.api.managers.*;
import com.swanclouds.api.session.SessionService;
import com.swanclouds.api.systems.*;
import com.swanclouds.api.task.TaskResourceService;
import com.swanclouds.api.task.TaskService;
import com.swanclouds.api.updates.FirmwareInventoryService;
import com.swanclouds.api.updates.UpdateService;
import com.swanclouds.redfish.account.AccountServiceImpl;
import com.swanclouds.redfish.account.HuaWeiAccountServiceImpl;
import com.swanclouds.redfish.account.LdapServiceImpl;
import com.swanclouds.redfish.chassis.*;
import com.swanclouds.redfish.event.EventResourceServiceImpl;
import com.swanclouds.redfish.event.SubscriptionsServiceImpl;
import com.swanclouds.redfish.managers.LogServiceImpl;
import com.swanclouds.redfish.managers.*;
import com.swanclouds.redfish.sessions.SessionServiceImpl;
import com.swanclouds.redfish.systems.*;
import com.swanclouds.redfish.task.TaskResourceServiceImpl;
import com.swanclouds.redfish.task.TaskServiceImpl;
import com.swanclouds.redfish.updates.FirmwareInventoryServiceImpl;
import com.swanclouds.redfish.updates.UpdateServiceImpl;

import java.util.Map;

/**
 * Simple API Provider which keeps internally Maps interface implementations as singletons
 *
 * @author Jeremy Unruh
 */
public class DefaultAPIProvider implements APIProvider {

    private static final Map<Class<?>, Class<?>> bindings = Maps.newHashMap();
    private static final Map<Class<?>, Object> instances = Maps.newConcurrentMap();

    /**
     * {@inheritDoc}
     */
    @Override
    public void initialize() {
        bind(SessionService.class, SessionServiceImpl.class);

        bind(SystemResourceService.class, SystemResourceServiceImpl.class);
        bind(SystemService.class, SystemServiceImpl.class);
        bind(ProcessorService.class, ProcessorServiceImpl.class);
        bind(MemoryService.class, MemoryServiceImpl.class);
        bind(StorageService.class, StorageServiceImpl.class);
        bind(VolumeService.class, VolumeServiceImpl.class);
        bind(BiosService.class, BiosServiceImpl.class);
        bind(LogServices.class, LogServicesImpl.class);
        bind(LogEntriesService.class, LogEntriesServiceImpl.class);
        bind(EthernetInterfaceService.class, EthernetInterfaceServiceImpl.class);
        bind(VLANService.class, VLANServiceImpl.class);
        bind(NetworkInterfaceService.class, NetworkInterfaceServiceImpl.class);
        bind(PCIeFunctionService.class, PCIeFunctionsServiceImpl.class);
        bind(NetworkBondService.class, NetworkBondServiceImpl.class);

        bind(ChassisResourceService.class, ChassisResourceServiceImpl.class);
        bind(ChassisService.class, ChassisServiceImpl.class);
        bind(ThermalService.class, ThermalServiceImpl.class);
        bind(PowerService.class, PowerServiceImpl.class);
        bind(DrivesService.class, DrivesServiceImpl.class);
        bind(NetworkAdaptersService.class, NetworkAdaptersServiceImpl.class);
        bind(PCIeDeviceService.class, PCIeDevicesServiceImpl.class);
        bind(NetworkPortsService.class, NetworkPortsServiceImpl.class);

        bind(ManagerResourceSerice.class, ManagerResourceServiceImpl.class);
        bind(ManagerService.class, ManagerServiceImpl.class);
        bind(NetworkProtocolService.class, NetworkProtocolServiceImpl.class);
        bind(EthernetInterfacesService.class, EthernetInterfacesServiceImpl.class);
        bind(VirtualMediaService.class, VirtualMediaServiceImpl.class);
        bind(LogService.class, LogServiceImpl.class);
        bind(SerialInterfacesService.class,SerialInterfacesServiceImpl.class);
        bind(SecurityService.class,SecurityServiceImpl.class);
        bind(SnmpService.class,SnmpServiceImpl.class);
        bind(SmtpService.class,SmtpServiceImpl.class);
        bind(KvmService.class,KvmServiceImpl.class);
        bind(NtpService.class,NtpServiceImpl.class);
        bind(SyslogService.class,SyslogServiceImpl.class);
        bind(LldpService.class,LldPServiceImpl.class);
        bind(DiagnosticService.class,DiagnosticServiceImpl.class);

        bind(AccountService.class, AccountServiceImpl.class);
        bind(LdapService.class, LdapServiceImpl.class);
        bind(HuaWeiAccountService.class, HuaWeiAccountServiceImpl.class);

        bind(UpdateService.class, UpdateServiceImpl.class);
        bind(FirmwareInventoryService.class, FirmwareInventoryServiceImpl.class);

        bind(TaskResourceService.class, TaskResourceServiceImpl.class);
        bind(TaskService.class, TaskServiceImpl.class);

        bind(EventResourceService.class, EventResourceServiceImpl.class);
        bind(SubscriptionsService.class, SubscriptionsServiceImpl.class);
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> T get(Class<T> api) {
        if (instances.containsKey(api))
            return (T) instances.get(api);

        if (bindings.containsKey(api)) {
            try {
                T impl = (T) bindings.get(api).newInstance();
                instances.put(api, impl);
                return impl;
            } catch (Exception e) {
                throw new ApiNotFoundException("API Not found for: " + api.getName(), e);
            }
        }
        throw new ApiNotFoundException("API Not found for: " + api.getName());
    }

    private void bind(Class<?> api, Class<?> impl) {
        bindings.put(api, impl);
    }
}
